package com.qiujie.service;

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiujie.dto.Response;
import com.qiujie.dto.ResponseDTO;
import com.qiujie.entity.Dept;
import com.qiujie.entity.Leave;
import com.qiujie.entity.Overtime;
import com.qiujie.entity.SalaryDeduct;
import com.qiujie.mapper.DeptMapper;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.math.BigDecimal;

import com.qiujie.enums.BusinessStatusEnum;
import com.qiujie.exception.ServiceException;



@Service
public class DeptService extends ServiceImpl<DeptMapper, Dept> {

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private LeaveService leaveService;

    @Autowired
    private SalaryDeductService salaryDeductService;

    @Autowired
    private OvertimeService overtimeService;

    // 新增部门（所有部门统一计算时间）
    public ResponseDTO add(Dept dept) {
        dept.setTotalWorkTime(calculateTotalWorkTime(dept));
        if (save(dept)) {
            return Response.success();
        }
        return Response.error();
    }

    //删除部门(增加关联校验)
    public ResponseDTO delete(Integer id) {
        checkAssociation(id);
        if (removeById(id)) {
            return Response.success();
        }
        return Response.error();
    }

    // 批量删除
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO deleteBatch(List<Integer> ids) {
        ids.forEach(this::checkAssociation);
        if (removeBatchByIds(ids)) {
            return Response.success();
        }
        return Response.error();
    }

    // 关联数据检查（修正后）
    private void checkAssociation(Integer deptId) {
        if (leaveService.count(new QueryWrapper<Leave>().eq("dept_id", deptId)) > 0) {
            throw new ServiceException(BusinessStatusEnum.DATA_ASSOCIATION);
        }
        if (salaryDeductService.count(new QueryWrapper<SalaryDeduct>().eq("dept_id", deptId)) > 0) {
            throw new ServiceException(BusinessStatusEnum.DATA_ASSOCIATION);
        }
        if (overtimeService.count(new QueryWrapper<Overtime>().eq("dept_id", deptId)) > 0) {
            throw new ServiceException(BusinessStatusEnum.DATA_ASSOCIATION);
        }
    }

    // 编辑部门（所有部门统一计算时间）
    public ResponseDTO edit(Dept dept) {
        dept.setTotalWorkTime(calculateTotalWorkTime(dept));
        if (updateById(dept)) {
            return Response.success();
        }
        return Response.error();
    }

    // 查询所有部门（平级结构）
    public ResponseDTO queryAll() {
        List<Dept> deptList = list(); // 直接查询所有部门（平级）
        return Response.success(deptList);
    }

    public ResponseDTO query(Integer id) {
        Dept dept = getById(id);
        return dept != null ? Response.success(dept) : Response.error();
    }

    // 分页列表查询（简化版）
    public ResponseDTO list(Integer current, Integer size, String name) {
        IPage<Dept> config = new Page<>(current, size);
        QueryWrapper<Dept> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(name)) {
            wrapper.like("name", name);
        }
        IPage<Dept> page = page(config, wrapper);

        Map<String, Object> map = new HashMap<>(3);
        map.put("pages", page.getPages());
        map.put("total", page.getTotal());
        map.put("list", page.getRecords());
        return Response.success(map);
    }



    // 数据导出（带标题行版本）
    public void export(HttpServletResponse response, String filename) throws Exception {
        List<Dept> list = list();

        // 1. 定义中文列名映射
        Map<String, String> columnAlias = new LinkedHashMap<String, String>() {{
            put("部门ID", "id");
            put("部门编码", "code");
            put("部门名称", "name");
            put("上午上班时间", "morStartTime");
            put("上午下班时间", "morEndTime");
            put("下午上班时间", "aftStartTime");
            put("下午下班时间", "aftEndTime");
            put("工作时长（H）", "totalWorkTime");
            put("备注", "remark");
            put("创建时间", "createTime");
        }};

        ExcelWriter writer = ExcelUtil.getWriter(true);
        try {
            // ==== 新增标题行逻辑 ====
            // 合并首行所有列（共9列，合并0-8列）
            writer.merge(columnAlias.size()-1, "部门信息表");

            // 设置标题样式
            Cell titleCell = writer.getCell(0, 0);
            Font titleFont = writer.createFont();
            titleFont.setBold(true);
            titleFont.setFontHeightInPoints((short)16);

            int[] columnWidths = {15, 18, 30, 12, 12, 12, 12, 15, 35, 20};
            for (int i = 0; i < columnWidths.length; i++) {
                writer.setColumnWidth(i, Math.min(columnWidths[i], 255));
            }

            CellStyle titleStyle = writer.createCellStyle();
            titleStyle.setFont(titleFont);
            titleStyle.setAlignment(HorizontalAlignment.CENTER);
            titleCell.setCellStyle(titleStyle);

            // 调整标题行高度
            writer.setRowHeight(0, 30);

            // ==== 原表头设置 ====
            // 设置表头从第二行开始（原第一行现在是标题）
            writer.setCurrentRow(1);
            columnAlias.forEach((alias, field) -> writer.addHeaderAlias(field, alias));
            writer.setOnlyAlias(true);


            // ==== 数据填充 ====
            List<Map<String, Object>> exportList = new ArrayList<>();
            for (Dept dept : list) {
                Map<String, Object> row = new LinkedHashMap<String, Object>() {{
                    put("id", dept.getId());
                    put("code", dept.getCode());
                    put("name", dept.getName());
                    put("morStartTime", formatTime(dept.getMorStartTime()));
                    put("morEndTime", formatTime(dept.getMorEndTime()));
                    put("aftStartTime", formatTime(dept.getAftStartTime()));
                    put("aftEndTime", formatTime(dept.getAftEndTime()));
                    put("totalWorkTime", dept.getTotalWorkTime());
                    put("remark", dept.getRemark());
                    put("createTime", dept.getCreateTime());
                }};
                exportList.add(row);
            }
            writer.write(exportList, true);

            // ==== 响应设置 ====
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(filename, "UTF-8") + ".xlsx");

            writer.flush(response.getOutputStream(), true);
        } finally {
            writer.close();
        }
    }

    private String formatTime(java.sql.Timestamp time) {
        return time != null ?
                time.toLocalDateTime().format(DateTimeFormatter.ofPattern("HH:mm")) :
                "";
    }


    // 数据导入（完整修正版）
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO imp(MultipartFile file) throws IOException {
        try (InputStream inputStream = file.getInputStream()) {
            ExcelReader reader = ExcelUtil.getReader(inputStream);

            // 字段映射（与导出模板严格一致）
            Map<String, String> aliasMap = new LinkedHashMap<String, String>() {{
                put("部门ID", "id");
                put("部门编码", "code");
                put("部门名称", "name");
                put("上午上班时间", "morStartTimeStr");
                put("上午下班时间", "morEndTimeStr");
                put("下午上班时间", "aftStartTimeStr");
                put("下午下班时间", "aftEndTimeStr");
                put("工作时长（H）", "totalWorkTime");
                put("备注", "remark");
                put("创建时间", "createTime");
            }};
            aliasMap.forEach(reader::addHeaderAlias);

            // 修正读取范围（从第3行开始读取，包含表头）
            List<Map<String,Object>> rawList = reader.read(1, 2, Integer.MAX_VALUE);

            if (rawList == null || rawList.isEmpty()) {
                return Response.error(BusinessStatusEnum.DATA_IMPORT_ERROR.getCode(),
                        "导入文件内容为空");
            }

            List<Dept> list = new ArrayList<>();
            for (int i = 0; i < rawList.size(); i++) {
                Map<String,Object> row = rawList.get(i);
                int excelRow = i + 3; // 实际Excel行号

                try {
                    Dept dept = new Dept();

                    // ==== 必填字段处理 ====
                    String name = getString(row, "name");
                    if (StringUtils.isBlank(name)) {
                        throw new ServiceException(
                                BusinessStatusEnum.DATA_IMPORT_ERROR.getCode(),
                                "第" + excelRow + "行：部门名称不能为空"
                        );
                    }
                    dept.setName(name.trim());

                    // ==== 时间字段处理 ====
                    dept.setMorStartTime(parseTime(getString(row, "morStartTimeStr"), excelRow));
                    dept.setMorEndTime(parseTime(getString(row, "morEndTimeStr"), excelRow));
                    dept.setAftStartTime(parseTime(getString(row, "aftStartTimeStr"), excelRow));
                    dept.setAftEndTime(parseTime(getString(row, "aftEndTimeStr"), excelRow));

                    // ==== 新增核心代码 ====
                    // 计算工作时间（必须在设置完时间字段后调用）
                    dept.setTotalWorkTime(calculateTotalWorkTime(dept));

                    list.add(dept);
                } catch (ServiceException e) {
                    return Response.error(e.getCode(), e.getMessage());
                }
            }

            return saveBatch(list) ? Response.success()
                    : Response.error(BusinessStatusEnum.DATA_IMPORT_ERROR.getCode(), "数据保存失败");
        } catch (Exception e) {
            return Response.error(BusinessStatusEnum.DATA_IMPORT_ERROR.getCode(),
                    "系统错误：" + e.getMessage());
        }
    }



    // 时间解析方法（增强版）
    private Timestamp parseTime(String timeStr, int excelRow) {
        if (StringUtils.isBlank(timeStr)) {
            throw new ServiceException(
                    BusinessStatusEnum.DATA_IMPORT_ERROR.getCode(),
                    "第" + excelRow + "行：时间字段不能为空"
            );
        }
        try {
            String cleanTime = timeStr.split("\\.")[0];
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm[:ss]");
            LocalTime time = LocalTime.parse(cleanTime, formatter);
            return Timestamp.valueOf(time.atDate(LocalDate.now()));
        } catch (DateTimeParseException e) {
            throw new ServiceException(
                    BusinessStatusEnum.DATA_IMPORT_ERROR.getCode(),
                    "第" + excelRow + "行：时间格式错误（应为HH:mm或HH:mm:ss）"
            );
        }
    }

    // 辅助方法：安全获取字符串
    private String getString(Map<String,Object> row, String key) {
        Object value = row.get(key);
        return value != null ? value.toString() : null;
    }






























    // 计算工作时间（保持原有逻辑）
    public BigDecimal calculateTotalWorkTime(Dept dept) {
        long morDiff = dept.getMorEndTime().getTime() - dept.getMorStartTime().getTime();
        long aftDiff = dept.getAftEndTime().getTime() - dept.getAftStartTime().getTime();
        return BigDecimal.valueOf((morDiff + aftDiff) / (1000 * 60 * 60.0));
    }
}

